package com.baidu.bulls.stock.user.service.impl;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.AbstractRule;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.baidu.bulls.stock.common.constans.GlobalConfig;
import com.baidu.bulls.stock.common.constans.GlobalSeq;
import com.baidu.bulls.stock.common.encrypt.EncryptUtil;
import com.baidu.bulls.stock.common.exception.BusinessException;
import com.baidu.bulls.stock.common.exception.ComponentException;
import com.baidu.bulls.stock.common.exception.constants.ApplicationErrorCodeEnum;
import com.baidu.bulls.stock.common.system.service.TradeGlobalConfigService;
import com.baidu.bulls.stock.entity.system.TradeGlobalConfig;
import com.baidu.bulls.stock.entity.user.Company;
import com.baidu.bulls.stock.entity.user.Institution;
import com.baidu.bulls.stock.entity.user.TradeAccount;
import com.baidu.bulls.stock.entity.user.TradeUser;
import com.baidu.bulls.stock.user.dao.CompanyMapper;
import com.baidu.bulls.stock.user.dao.IStockUserMapper;
import com.baidu.bulls.stock.user.dao.InstitutionMapper;
import com.baidu.bulls.stock.user.dao.TradeAccountMapper;
import com.baidu.bulls.stock.user.service.StockUserService;
import com.baidu.stock.common.web.vo.user.TradeUserVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Log4j2
public class StockUserServiceImpl extends ServiceImpl<IStockUserMapper,TradeUser> implements StockUserService {

    @Autowired
    private TradeAccountMapper tradeAccountMapper;
//    @Autowired
//    private TradeGlobalConfigService tradeGlobalConfigService;

    @Autowired
    private IStockUserMapper stockUserDao;
    @Autowired
    private CompanyMapper companyMapper;
    @Autowired
    private InstitutionMapper institutionMapper;
    @Autowired
    private TradeGlobalConfigService tradeGlobalConfigServiceImpl;

    /**
     * block降级处理
     *
     * @param userNo
     * @param userPwd
     * @param ex
     * @return
     */
    public TradeUser userLoginHandle(String userNo, String userPwd, BlockException ex) throws ComponentException {
        log.error("userLogin flow limit ,call userLoginHandle:{}", ex.getMessage());
        //获取熔断限流规则
        AbstractRule abstractRule = ex.getRule();
        //降级处理
        if (abstractRule instanceof DegradeRule) {
            //熔断,sentinel 1.6.0一下版本，只支持抛出DegradeException异常的处理
            throw new ComponentException(ApplicationErrorCodeEnum.SYS_BUSY);
        } else if (abstractRule instanceof FlowRule) {
            //限流
            throw new ComponentException(ApplicationErrorCodeEnum.SYS_FLOW);
        }
        throw new ComponentException(ApplicationErrorCodeEnum.FAILURE);
    }

    /**
     * 用户登陆
     *
     * @param userNo
     * @param userPwd
     * @return
     */
    @Override
    //blockHandler和fallback两个同时配置，只会进入blockHandler
    @SentinelResource(value = "userLogin", blockHandler = "userLoginHandle" ,fallback = "fallbackHandle")
    public TradeUser userLogin(String userNo, String userPwd) throws ComponentException {
        if ("error".equals(userNo)) {
            throw new ComponentException(ApplicationErrorCodeEnum.FAILURE);
        }
        LambdaQueryWrapper<TradeUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StringUtils.isNotEmpty(userNo),TradeUser::getUserNo,userNo);

        // 获取用户对象
        TradeUser tradeUser = stockUserDao.selectOne(wrapper);
        if (null == tradeUser) {
            throw new ComponentException(ApplicationErrorCodeEnum.USER_NOT_FOUND);
        }
        // 用户密码加密判断
        String encryptPassword = EncryptUtil.encryptSigned(userPwd);
        boolean pwdMatch = tradeUser.getUserPwd().equals(encryptPassword);
        if (!pwdMatch) {
            log.error(ApplicationErrorCodeEnum.USER_PWD_ERROR);
            throw new ComponentException(ApplicationErrorCodeEnum.USER_PWD_ERROR);
        }
        return tradeUser;
    }

    /**
     * 用户注册
     */
    @Override
    public TradeUser userRegister(TradeUserVo vo) throws ComponentException, BusinessException {
        TradeUser newTradeUser = new TradeUser();

        //检查用户是否注册
        List<TradeUser> tradeUsers = checkUserRegister(vo.getUserNo(), vo.getEmail(), vo.getPhone());
        if (!CollectionUtils.isEmpty(tradeUsers)){
            throw new BusinessException(ApplicationErrorCodeEnum.USER_EXISTS);
        }
        //检查公司是否存在
        Company company = checkCompany(vo.getCompanyId());
        if (company == null){
            throw new BusinessException(ApplicationErrorCodeEnum.USER_COMPANY_NOT_FOUND);
        }
        //完善用户信息，进行用户保存
        BeanUtils.copyProperties(vo,newTradeUser);
        newTradeUser.setUserNo(userGeneratorUserNo());
        newTradeUser.setUserPwd(EncryptUtil.encryptSigned(vo.getUserPwd()));
        Institution institution = institutionMapper.selectByCompanyId(vo.getCompanyId());
        if (institution != null){
            newTradeUser.setInstitutionId(institution.getId());
            newTradeUser.setInstitutionTypeId(institution.getInstitutiontypeid());
            newTradeUser.setCompanyName(company.getCompanyname());
        }
        stockUserDao.insert(newTradeUser);

        //新增账号
        TradeGlobalConfig tradeGlobalConfigByCode = tradeGlobalConfigServiceImpl.getTradeGlobalConfigByCode(GlobalConfig.REG_OPEN_ACCOUNT);
        if (tradeGlobalConfigByCode != null && GlobalConfig.VALUE_TRUE.equals(tradeGlobalConfigByCode.getValue())){
            //如果存在该配置项，而且值为Y，代表注册即开户
            //生成交易账户信息
            TradeAccount tradeAccount = new TradeAccount();
            tradeAccount.setAccountno(userGeneratorUserAccountNo());
            tradeAccount.setActivetime(LocalDateTime.now());
            tradeAccount.setInstitutiontypeid(institution.getInstitutiontypeid());
            tradeAccount.setInstitutionid(institution.getId());
            tradeAccount.setUserid(newTradeUser.getId());
            // 先设置为系统默认组别
            tradeAccount.setTradeGroupId(1L);
            tradeAccount.setStatus(GlobalConfig.STATUS_VALID);
            tradeAccountMapper.insert(tradeAccount);
        }
        //TODO 发送邮件，短信，后面对接阿里云补上

        return newTradeUser;
    }

    private Company checkCompany(Long companyId) {
        Company company = companyMapper.selectById(companyId);
        if (company == null){
            return null;
        }
        return company;
    }

    /**
     * 检查用户是否注册
     *
     * @param userNo
     * @param email
     * @param phone
     */
    private List<TradeUser> checkUserRegister(String userNo, String email, String phone) {
        Map<String, Object> map = new HashMap<>();
        if (StringUtils.isNotEmpty(userNo)) {
            map.put("userNo", userNo);
        }
        if (StringUtils.isNotEmpty(email)) {
            map.put("email", email);
        }
        if (StringUtils.isNotEmpty(phone)) {
            map.put("phone", phone);
        }
        return stockUserDao.selectByMap(map);
    }

    /**
     * 自动生成全局用户号
     * @return
     */
    public String userGeneratorUserNo() {
        Long nextSeqId = tradeGlobalConfigServiceImpl.getNextSeqId(GlobalSeq.USER_NO);
        log.info("新增全局用户编号：{}", nextSeqId);
        return String.format("%08d", nextSeqId);
    }

    /**
     * 自动生成全局账户号
     * @return
     */
    public String userGeneratorUserAccountNo() {
        Long nextSeqId = tradeGlobalConfigServiceImpl.getNextSeqId(GlobalSeq.USER_ACC);
        log.info("新增全局用户编号：{}", nextSeqId);
        return String.format("%08d", nextSeqId);
    }
}
